﻿Imports Aricie.DNN.Modules.LuceneSearch.Business
Imports Components.Lucene.ExistingIndex

Namespace Components.Lucene.IndexMerger

    ''' <summary>
    ''' Comparer that sorts new items according to the existing index structure
    ''' </summary>
    ''' <remarks></remarks>
    Public Class IndexMergeSorter
        Implements IComparer(Of LuceneSearchItemInfo)

        Private _CurrentIndexStructure As ExistingIndexStructure(Of ExistingIndexDocumentSmartOrdering)
        Private _CurrentComparisonDate As DateTime = DateTime.Now

        Public Property OldDocumentsTurnOver As Integer
        Public Property SmartOrderingMethod As Func(Of ExistingIndexDocumentSmartOrdering, Long) = AddressOf SmartValueOrderingMethod

        Public Sub New(IndexStructure As ExistingIndexStructure(Of ExistingIndexDocumentSmartOrdering))
            _CurrentIndexStructure = IndexStructure
        End Sub

        Public Function Compare(x As LuceneSearchItemInfo, y As LuceneSearchItemInfo) As Integer Implements System.Collections.Generic.IComparer(Of LuceneSearchItemInfo).Compare
            ' if one of this item doesn't exist already in the index, it takes precedence because we want to index data as quickly as possible
            Dim ExistingIndexDocumentX As ExistingIndexDocumentSmartOrdering = Nothing
            Dim ExistingIndexDocumentY As ExistingIndexDocumentSmartOrdering = Nothing

            _CurrentIndexStructure.UidToDocument.TryGetValue(x.UniqueId, ExistingIndexDocumentX)
            _CurrentIndexStructure.UidToDocument.TryGetValue(y.UniqueId, ExistingIndexDocumentY)

            If (ExistingIndexDocumentX Is Nothing AndAlso ExistingIndexDocumentY Is Nothing) Then
                Return 0 ' both documents are new to this index, let's give them the same precedence
            ElseIf ExistingIndexDocumentX Is Nothing Then
                Return -1 ' Document X is new to this index so it goes first
            ElseIf ExistingIndexDocumentY Is Nothing Then
                Return 1 ' Document Y is new to this index so it goes first
            End If

            ' both documents already exist in the index, now the only thing that will determine order is their relative age and frequency of modification
            
            If ExistingIndexDocumentX.HasIdentifier AndAlso ExistingIndexDocumentY.HasIdentifier Then
                ' both documents have an identifier, we can compare the values they expose
                Dim SmartValueX As Long = ExistingIndexDocumentX.GetSmartOrderingValue(SmartOrderingMethod)
                Dim SmartValueY As Long = ExistingIndexDocumentY.GetSmartOrderingValue(SmartOrderingMethod)

                If SmartValueX > SmartValueY Then
                    Return 1
                ElseIf SmartValueX < SmartValueY Then
                    Return -1
                Else
                    Return 0
                End If
            End If

            'if one or more document lacks an identifier
            If Not ExistingIndexDocumentX.HasIdentifier AndAlso Not ExistingIndexDocumentY.HasIdentifier Then
                Return 0
            End If
            If Not ExistingIndexDocumentX.HasIdentifier Then
                Return -1
            End If
            ' if we are here, document Y has no identifier
            Return 1
            
        End Function

        Public Function SmartValueOrderingMethod(CurrentDocument As ExistingIndexDocumentSmartOrdering) As Long

            Dim SmartValue As Long

            Dim ageLastIndexed As TimeSpan = _CurrentComparisonDate - CurrentDocument.IndexedDate
            Dim ageLastModified As TimeSpan = _CurrentComparisonDate - CurrentDocument.ModifiedDate
            If OldDocumentsTurnOver < 2 OrElse ageLastModified = ageLastIndexed Then
                ' we don't have enough data to determine how the time window between indexation determines the priority of this document
                SmartValue = ageLastIndexed.Ticks
            Else
                ' we calculate this value depending on the discrespancy between modification and indexing dates
                Dim val As Double = ageLastIndexed.Ticks / OldDocumentsTurnOver + ((OldDocumentsTurnOver - 1) / OldDocumentsTurnOver) * ((ageLastIndexed.Ticks / ageLastModified.Ticks) * ageLastIndexed.Ticks)
                SmartValue = Convert.ToInt64(val)
            End If

            Return SmartValue
        End Function
    End Class

End Namespace